﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Data;
using System.Data.Entity;

namespace Husb.Data
{
    public abstract class RepositoryBase<TDbContext, T> : IRepository<T>
        where T : class
        where TDbContext : DBContext, new()
    {
        private TDbContext dataContext;
        private readonly IDbSet<T> dbSet;
        protected RepositoryBase(IDBFactory<TDbContext> databaseFactory)
        {
            DatabaseFactory = databaseFactory;
            dbSet = DataContext.Set<T>();
        }

        protected IDBFactory<TDbContext> DatabaseFactory
        {
            get;
            private set;
        }

        protected TDbContext DataContext
        {
            get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
        }

        #region IRepository<T>

        public virtual void Add(T entity)
        {
            dbSet.Add(entity);
        }

        public virtual void Update(T entity)
        {
            dbSet.Attach(entity);
            dataContext.Entry(entity).State = EntityState.Modified;
        }

        public virtual void Delete(T entity)
        {
            dbSet.Remove(entity);
        }

        public virtual void Delete(Expression<Func<T, bool>> where)
        {
            IEnumerable<T> objects = dbSet.Where<T>(where).AsEnumerable();
            foreach (T obj in objects)
                dbSet.Remove(obj);
        }

        public virtual T GetById(long id)
        {
            return dbSet.Find(id);
        }

        public virtual T GetById(string id)
        {
            return dbSet.Find(id);
        }

        public virtual int Count(Expression<Func<T, bool>> where = null)
        {
            //if (where == null)
            //    return dbSet.Count();
            //return dbSet.Count(where);
            int count = 0;
            try
            {
                if (where == null)
                {
                    count = dbSet.Count();
                }
                else
                {
                    count = dbSet.Count(where);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return count;

        }

        public virtual IEnumerable<T> GetAll()
        {
            return dbSet.ToList();
        }

        public virtual IEnumerable<T> GetMany(Expression<Func<T, bool>> where = null,
            Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
            string includeProperties = "")
        {
            IQueryable<T> query = dbSet;

            if (where != null)
            {
                query = query.Where(where);
            }

            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                return orderBy(query);//.ToList();
            }
            else
            {
                return query;//.ToList();
            }

            //if (where == null)
            //{
            //    return dbSet.ToList();
            //}
            //else
            //{
            //    return dbSet.Where(where).ToList();
            //}
        }

        //public T Get(Expression<Func<T, bool>> where)
        //{
        //    return dbSet.Where(where).FirstOrDefault<T>();
        //}


        public T GetById(int id)
        {
            return dbSet.Find(id);
        }

        public T GetById(Guid id)
        {
            return dbSet.Find(id);
        }

        public IEnumerable<T> GetPaged(int maximumRows = 20, 
            int startRowIndex = 0, 
            Expression<Func<T, bool>> where = null, 
            Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, 
            string includeProperties = "")
        {
            IQueryable<T> query = dbSet;

            if (where != null)
            {
                query = query.Where(where);
            }

            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                return orderBy(query).Skip(startRowIndex).Take(maximumRows);//.ToList();
            }
            else
            {
                // query 应该是已经有Order By的结果
                return query.Skip(startRowIndex).Take(maximumRows);//.ToList();

            }
        }
        #endregion
    }
}
